<template>
	<view v-if="validity" class="bubble" @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="touchMove" @touchend.stop.prevent="touchEnd">
		<view class="bubble-zone" :id="zoneId" :style="{ width: size + 'rpx', height: size + 'rpx', transform: bCircleTransform }">
			<view class="bubble-content"><slot name="bubble"></slot></view>
		</view>
		<!--  -->
		<canvas v-if="canvasHeight && canvasStatus" class="bubble-canvas" :canvas-id="canvasId" :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"></canvas>
	</view>
</template>

<script>
export default {
	props: {
		size: {
			type: Number,
			default: 40
		},
		color: {
			type: String,
			default: '#f03c3c'
		},
		index: {
			type: [String, Number],
			default: ''
		},
		auto: {
			type: Boolean,
			default: true
		}
	},
	watch: {
		//设置虚拟圆心的尺寸
		size: {
			handler(newVal, oldVal, changedPath) {
				this.radius = uni.upx2px(newVal) / 2;
			},
			immediate: true
		}
	},
	data() {
		return {
			//控制canvas出现
			canvasStatus: false,
			canvasHeight: null,
			canvasWidth: null,
			validity: true,
			radius: null,
			ctx: null,

			minRadius: 5,
			offset: {
				x: 0,
				y: 0
			},
			// 每一帧的时长，频率参考为60HZ
			frameDuration: 1000 / 60,
			// 动画时长，200ms暂定
			animationDuration: 60,
			bCircleTransform: '',
			identity: this.$u.guid()
		};
	},
	mounted() {
		const systemInfo = uni.getSystemInfoSync();
		this.canvasWidth = systemInfo.windowWidth;
		this.canvasHeight = systemInfo.windowHeight;
		this.$nextTick(() => {
			const ctx = uni.createCanvasContext(this.canvasId, this);
			const query = uni.createSelectorQuery().in(this);
			query.select('#' + this.zoneId).boundingClientRect(res => {
			 const left = (res.left + res.right) / 2;
			 const top = (res.top + res.bottom) / 2;
			 this.offset = {
			 	x: left,
			 	y: top
			 };
			}).exec();
			
			
			// this.$u.getRect('#' + this.zoneId).then(res => {
			// 	const left = (res.left + res.right) / 2;
			// 	const top = (res.top + res.bottom) / 2;
			// 	this.offset = {
			// 		x: left,
			// 		y: top
			// 	};
			// });

			this.ctx = ctx;
		});
	},
	computed: {
		zoneId: function() {
			return `zone-${this.identity}`;
		},
		canvasId: function() {
			return `canvas-${this.identity}`;
		},
		smallSize: function() {
			return Math.round(this.radius * 0.6);
		},
		maxDistance: function() {
			return this.radius * 7 > 200 ? 200 : this.radius * 7;
		},
		//帧数
		franeNumber: function() {
			return this.animationDuration / this.frameDuration;
		}
	},
	methods: {
		touchStart(e) {
			this.canvasStatus = true;
		},
		touchMove(e) {
			console.log(this.offset);
			const { pageX, pageY } = e.touches[0];

			let currRadius = this.calcCurrRadius(pageX, pageY);

			const point = this.getPoint(this.offset.x, this.offset.y, pageX, pageY, currRadius, this.radius);
			this.drawCanvas(point);
		},
		touchEnd(e) {
			const { pageX, pageY } = e.changedTouches[0];
			let currRadius = this.calcCurrRadius(pageX, pageY);
			const { currentDistance, mCircle, bCircle } = this.getPoint(this.offset.x, this.offset.y, pageX, pageY, currRadius, this.radius);
			if (currentDistance < this.maxDistance) {
				const distanceX = mCircle.x - bCircle.x;
				const distanceY = mCircle.y - bCircle.y;
				// 向下取整2位小数
				const diffX = parseInt((distanceX / this.franeNumber) * 100) / 100;
				const diffY = parseInt((distanceY / this.franeNumber) * 100) / 100;
				const animationPointList = [];
				for (let i = 0; i < this.franeNumber; i++) {
					const x = bCircle.x + (i + 1) * diffX;
					const y = bCircle.y + (i + 1) * diffY;
					animationPointList.push({ x, y, currRadius: this.calcCurrRadius(x, y) });
				}
				this.initBackAnimation(animationPointList);
			} else {
				if (this.auto) {
					this.validity = false;
				}
				this.$emit('remove', { index: this.index });
			}
			
		},
		//计算贝塞尔结束点构成圆的半径
		calcCurrRadius(x, y) {
			const moveOffsetX = x - this.offset.x;
			const moveOffsetY = y - this.offset.y;
			const distance = Math.sqrt(Math.pow(moveOffsetX, 2) + Math.pow(moveOffsetY, 2));
			let currRadius = Math.round(this.smallSize - distance / 20);
			if (currRadius < this.minRadius) {
				currRadius = this.minRadius;
			}
			return currRadius;
		},
		initBackAnimation(pointList, index = 0) {
			const point = this.getPoint(this.offset.x, this.offset.y, pointList[index].x, pointList[index].y, pointList[index].currRadius, this.radius);
			this.drawCanvas(point);
			if (index < pointList.length - 1) {
				setTimeout(() => {
					this.initBackAnimation(pointList, index + 1);
				}, this.frameDuration);
			} else {
				this.ctx.draw(false);
				this.bCircleTransform = null;
				this.canvasStatus = false;
			}
		},
		//获取粘滞效果的起止点和贝塞尔曲线的控制点
		getPoint(sx, sy, ex, ey, r1, r2) {
			const deltaX = ex - sx;
			const deltaY = ey - sy;
			const currentDistance = Math.sqrt(Math.pow(deltaY, 2) + Math.pow(deltaX, 2));
			if (currentDistance == 0) {
				return;
			}
			const sinAngel = deltaY / currentDistance;
			const cosAngel = deltaX / currentDistance;
			const control = {};
			const point = {};

			// control.x = sx + deltaX / 2;
			// control.y = sy + deltaY / 2;

			point.p1x = sx - r1 * sinAngel;
			point.p1y = sy + r1 * cosAngel;
			point.p2x = ex - r2 * sinAngel;
			point.p2y = ey + r2 * cosAngel;
			point.p3x = ex + r2 * sinAngel;
			point.p3y = ey - r2 * cosAngel;
			point.p4x = sx + r1 * sinAngel;
			point.p4y = sy - r1 * cosAngel;

			control.x = (point.p1x + point.p2x + point.p3x + point.p4x) / 4;
			control.y = (point.p1y + point.p2y + point.p3y + point.p4y) / 4;

			const mCircle = { x: (point.p1x + point.p4x) / 2, y: (point.p1y + point.p4y) / 2 };
			const bCircle = { x: (point.p2x + point.p3x) / 2, y: (point.p2y + point.p3y) / 2 };

			return { control, point, currentDistance, mCircle, bCircle };
		},
		//绘制canvas
		drawCanvas(obj) {
			const { control, point, currentDistance, mCircle, bCircle } = obj;
			if (currentDistance < this.maxDistance) {
				this.ctx.beginPath();
				this.ctx.setFillStyle(this.color);

				this.ctx.arc(mCircle.x, mCircle.y, this.minRadius, 0, 2 * Math.PI);
				this.ctx.fill();

				this.ctx.arc(bCircle.x, bCircle.y, this.radius, 0, 2 * Math.PI);
				this.ctx.fill();

				this.ctx.moveTo(point.p4x, point.p4y);
				this.ctx.lineTo(point.p1x, point.p1y);
				// this.ctx.lineTo(point.p2x, point.p2y);
				this.ctx.quadraticCurveTo(control.x, control.y, point.p2x, point.p2y);

				this.ctx.lineTo(point.p3x, point.p3y);
				// this.ctx.moveTo(point.p3x, point.p3y);
				// this.ctx.lineTo(point.p4x, point.p4y);
				this.ctx.quadraticCurveTo(control.x, control.y, point.p4x, point.p4y);
				this.ctx.fill();
			}

			this.bCircleTransform = `translate(${bCircle.x - this.offset.x}px,${bCircle.y - this.offset.y}px)`;
			this.ctx.draw(false);
		}
	}
};
</script>

<style lang="scss">
.bubble {
	position: relative;
	&::before {
		content: '';
		display: table;
	}
	.bubble-zone {
		transform-origin: center;
		position: relative;
		z-index: 999;
		transform-origin: center;

		//备用

		.bubble-content {
			position: absolute;
			left: 50%;
			top: 0;
			transform: translateX(-50%);
			z-index: 999;
		}
	}

	.bubble-canvas {
		position: fixed;
		bottom: var(--window-bottom);
		left: 0;
		z-index: 108;
	}
	.dot {
		width: 40rpx;
		height: 40rpx;
		background-color: #f03c3c;
		margin-top: 50rpx;
		margin-left: 100rpx;

		transform-origin: center;
	}
}
</style>
